/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.basics.bean;

import java.util.AbstractMap;
import java.util.Comparator;
import java.util.Set;

import org.springframework.util.ObjectUtils;

import com.genia.toolbox.basics.process.Comparators;

/**
 * a {@link java.util.Map} that is sorted in respect to the keys, but that does
 * work with comparator that returns 0 for object that are not equals.
 * 
 * @param <K>
 *          the type of the keys.
 * @param <V>
 *          the type of the values.
 */
public class WeakSortedMap<K, V>
    extends AbstractMap<K, V>
{

  /**
   * the {@link Entry} to use with this map.
   */
  private class WeakSortedMapEntry
      implements Entry<K, V>, Comparable<WeakSortedMapEntry>
  {

    /**
     * the key.
     */
    private K key;

    /**
     * the value.
     */
    private V value;



    /**
     * constructor.
     * 
     * @param key
     *          the key
     * @param value
     *          the value
     */
    public WeakSortedMapEntry(K key, V value)
    {
      this.key = key;
      this.value = value;
    }



    /**
     * the comparator method.
     * 
     * @param object
     *          the other object to compare to
     * @return -1, 0 or 1 depending on the order of the elements
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    public int compareTo(WeakSortedMapEntry object)
    {
      return comparator.compare(getKey(), object.getKey());
    }



    /**
     * the equality method.
     * 
     * @param object
     *          the object be compared with
     * @return <code>true</code> if the two objects represents the same
     *         element.
     */
    @Override
    public boolean equals(Object object)
    {
      if (object == this) {
        return true;
      }
      if (object == null) {
        return false;
      }
      if (object.getClass() == this.getClass()) {
        WeakSortedMapEntry other = (WeakSortedMapEntry) object;
        return ObjectUtils.nullSafeEquals(getKey(), other.getKey());
      }
      return false;
    }



    /**
     * getter for the key property.
     * 
     * @return the key
     */
    public K getKey()
    {
      return key;
    }



    /**
     * getter for the value property.
     * 
     * @return the value
     */
    public V getValue()
    {
      return value;
    }



    /**
     * returns the hash code of this object.
     * 
     * @return the hash code of this object.
     */
    @Override
    public int hashCode()
    {
      return getKey().hashCode();
    }



    /**
     * setter for the key property.
     * 
     * @param key
     *          the key to set
     */
    public void setKey(K key)
    {
      this.key = key;
    }



    /**
     * setter for the value property.
     * 
     * @param value
     *          the value to set
     * @return the old value
     */
    public V setValue(V value)
    {
      V res = this.value;
      this.value = value;
      return res;
    }

  }

  /**
   * the {@link Comparator} to use to compare keys.
   */
  @SuppressWarnings("unchecked")
  private transient Comparator<? super K> comparator = (Comparator<? super K>) Comparators.NATURAL_COMPARATOR;

  /**
   * the {@link Set} containing all the entries.
   */
  private transient final Set<WeakSortedMapEntry> entries = new WeakSortedSet<WeakSortedMapEntry>();



  /**
   * constructor.
   */
  public WeakSortedMap()
  {
    // Do nothing.
  }



  /**
   * constructor.
   * 
   * @param comparator
   *          the {@link Comparator} to use to compare keys
   */
  public WeakSortedMap(Comparator<? super K> comparator)
  {
    this.comparator = comparator;
  }



  /**
   * returns the {@link Set} containing all the entries.
   * 
   * @return the {@link Set} containing all the entries
   * @see java.util.AbstractMap#entrySet()
   */
  @SuppressWarnings("unchecked")
  @Override
  public Set<Entry<K, V>> entrySet()
  {
    return (Set) entries;
  }



  /**
   * Associates the specified value with the specified key in this map (optional
   * operation). If the map previously contained a mapping for this key, the old
   * value is replaced.
   * 
   * @param key
   *          key with which the specified value is to be associated.
   * @param value
   *          value to be associated with the specified key.
   * @return previous value associated with specified key, or <tt>null</tt> if
   *         there was no mapping for key. (A <tt>null</tt> return can also
   *         indicate that the map previously associated <tt>null</tt> with
   *         the specified key, if the implementation supports <tt>null</tt>
   *         values.)
   */
  @Override
  public V put(K key, V value)
  {
    V oldValue = get(value);
    entries.add(new WeakSortedMapEntry(key, value));
    return oldValue;
  }

}
